View Javadoc
1   package org.apache.maven.surefire.junitcore;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.ArrayList;
23  import java.util.Collections;
24  import java.util.List;
25  import java.util.concurrent.ExecutionException;
26  import java.util.concurrent.ExecutorService;
27  import java.util.concurrent.Executors;
28  import java.util.concurrent.ThreadFactory;
29  
30  import org.apache.maven.surefire.util.internal.DaemonThreadFactory;
31  import org.junit.runner.Computer;
32  import org.junit.runner.Runner;
33  import org.junit.runners.ParentRunner;
34  import org.junit.runners.Suite;
35  import org.junit.runners.model.InitializationError;
36  import org.junit.runners.model.RunnerBuilder;
37  import org.junit.runners.model.RunnerScheduler;
38  
39  /**
40   * Since SUREFIRE 2.18 this class is deprecated.
41   * Please use {@link org.apache.maven.surefire.junitcore.pc.ParallelComputerBuilder} instead.
42   *
43   * @author Kristian Rosenvold
44   */
45  @Deprecated
46  public class ConfigurableParallelComputer
47      extends Computer
48  {
49      private static final ThreadFactory DAEMON_THREAD_FACTORY = DaemonThreadFactory.newDaemonThreadFactory();
50  
51      private final boolean fClasses;
52  
53      private final boolean fMethods;
54  
55      private final boolean fixedPool;
56  
57      private final ExecutorService fService;
58  
59      private final List<AsynchronousRunner> nonBlockers =
60          Collections.synchronizedList( new ArrayList<AsynchronousRunner>() );
61  
62  
63      public ConfigurableParallelComputer()
64      {
65          this( true, true, Executors.newCachedThreadPool( DAEMON_THREAD_FACTORY ), false );
66      }
67  
68      public ConfigurableParallelComputer( boolean fClasses, boolean fMethods )
69      {
70          this( fClasses, fMethods, Executors.newCachedThreadPool( DAEMON_THREAD_FACTORY ), false );
71      }
72  
73      public ConfigurableParallelComputer( boolean fClasses, boolean fMethods, Integer numberOfThreads, boolean perCore )
74      {
75          this( fClasses, fMethods,
76                Executors.newFixedThreadPool(
77                    numberOfThreads * ( perCore ? Runtime.getRuntime().availableProcessors() : 1 ),
78                    DAEMON_THREAD_FACTORY ),
79                true );
80      }
81  
82      private ConfigurableParallelComputer( boolean fClasses, boolean fMethods, ExecutorService executorService,
83                                            boolean fixedPool )
84      {
85          this.fClasses = fClasses;
86          this.fMethods = fMethods;
87          fService = executorService;
88          this.fixedPool = fixedPool;
89      }
90  
91      @SuppressWarnings( { "UnusedDeclaration" } )
92      public void close()
93          throws ExecutionException
94      {
95          for ( AsynchronousRunner nonBlocker : nonBlockers )
96          {
97              nonBlocker.waitForCompletion();
98          }
99  
100         fService.shutdown();
101         try
102         {
103             if ( !fService.awaitTermination( 10, java.util.concurrent.TimeUnit.SECONDS ) )
104             {
105                 throw new RuntimeException( "Executor did not shut down within timeout" );
106             }
107         }
108         catch ( InterruptedException e )
109         {
110             throw new RuntimeException( e );
111         }
112     }
113 
114     private Runner parallelize( Runner runner, RunnerScheduler runnerInterceptor )
115     {
116         if ( runner instanceof ParentRunner<?> )
117         {
118             ( (ParentRunner<?>) runner ).setScheduler( runnerInterceptor );
119         }
120         return runner;
121     }
122 
123     private RunnerScheduler getMethodInterceptor()
124     {
125         if ( fClasses && fMethods )
126         {
127             final AsynchronousRunner blockingAsynchronousRunner = new AsynchronousRunner( fService );
128             nonBlockers.add( blockingAsynchronousRunner );
129             return blockingAsynchronousRunner;
130         }
131         return fMethods ? new AsynchronousRunner( fService ) : new SynchronousRunner();
132     }
133 
134     private RunnerScheduler getClassInterceptor()
135     {
136         if ( fClasses )
137         {
138             return fMethods ? new SynchronousRunner() : new AsynchronousRunner( fService );
139         }
140         return new SynchronousRunner();
141     }
142 
143     @Override
144     public Runner getSuite( RunnerBuilder builder, java.lang.Class<?>[] classes )
145         throws InitializationError
146     {
147         Runner suite = super.getSuite( builder, classes );
148         return fClasses ? parallelize( suite, getClassInterceptor() ) : suite;
149     }
150 
151     @Override
152     protected Runner getRunner( RunnerBuilder builder, Class<?> testClass )
153         throws Throwable
154     {
155         Runner runner = super.getRunner( builder, testClass );
156         return fMethods && !isTestSuite( testClass ) ? parallelize( runner, getMethodInterceptor() ) : runner;
157     }
158 
159     private boolean isTestSuite( Class<?> testClass )
160     {
161         // Todo: Find out how/if this is enough
162         final Suite.SuiteClasses annotation = testClass.getAnnotation( Suite.SuiteClasses.class );
163         return ( annotation != null );
164     }
165 
166     @Override
167     public String toString()
168     {
169         return "ConfigurableParallelComputer{" + "classes=" + fClasses + ", methods=" + fMethods + ", fixedPool="
170             + fixedPool + '}';
171     }
172 
173 }